#ifndef __OSAPICC16_H__
#define __OSAPICC16_H__

    
    
#undef OS_SMSG_SIZE
#define OS_SMSG_SIZE    sizeof(OST_SMSG)


//______________________________________________________________________________
//******************************************************************************

static volatile char _fsr @ 0x4;
static volatile char _status @ 0x3;
static volatile char _indf @ 0x0;
static volatile char _pcl @ 0x02;
static volatile char _pclath @ 0x0A;
static volatile char _intcon @ 0x0B;

#define _FSR_TYPE            unsigned char
#define _PIC18_ERRATA_NOP()     // Empty macro for this type of PICs


//------------------------------------------------------------------------------



// Type of code pointer (used in TCB)
#define OST_CODE_POINTER    unsigned int    


#define OST_TASK_POINTER   OS_TASKS_BANK OST_TCB * 



#define OS_CLRWDT()   asm(" clrwdt ");
#define OS_ClrWdt()   asm(" clrwdt ");
#define OS_SLEEP()    asm(" sleep  ");
#define OS_Sleep()    asm(" sleep  ");



//______________________________________________________________________________
/******************************************************************************
 * Switch control routines:
 *
 *  _OS_JumpToTask() - jump indirectly from kernel (OS_Sched) into task
 *  _OS_SaveRetAddr() - task return to this point 
 *
 *  _OS_GetReturnPoint() - exit from task and save context
 *  _OS_CallGetReturnPoint() - save context without exiting task
 *  _OS_ReturnNoSave() - exit task without saving context
 *
 *******************************************************************************/


    
#if !defined(_BANKBITS_)
#define _BANKBITS_  2
#endif


//------------------------------------------------------------------------------
#if OS_BANK_TASKS >= 2
    #define _SET_TASK_IRP()      _status |= 0x80
#else
    #if _BANKBITS_ >= 2 
        #define _SET_TASK_IRP()      _status &= ~0x80
    #else
        #define _SET_TASK_IRP()      
    #endif
#endif
//------------------------------------------------------------------------------

#if     _BANKBITS_ == 0

    #define _OS_SAVE_RP0_RP1()
    #define _OS_RESTORE_RP0_RP1()

#elif   _BANKBITS_ == 1

    #define _OS_SAVE_RP0_RP1()                              \
        asm("   btfsc   __status, 5       ");               \
        asm("   iorlw   0x20     ");                        \

    #define _OS_RESTORE_RP0_RP1()                           \
        asm("   btfsc   __OS_tempH, 5     ");               \
        asm("   bsf     __status, 5");                      \

#elif   _BANKBITS_ == 2

    #define _OS_SAVE_RP0_RP1()                              \
        asm("   btfsc   __status, 5       ");               \
        asm("   iorlw   0x20     ");                        \
        asm("   btfsc   __status, 6       ");               \
        asm("   iorlw   0x40     ");

    #define _OS_RESTORE_RP0_RP1()                           \
        asm("   movf    __OS_tempH, w     ");               \
        asm("   andlw   0x60     ");                        \
        asm("   iorwf   __status, f");                      \

#endif




//------------------------------------------------------------------------------

#define _OS_JumpToTask()                                                    \
    {                                                                       \
        asm("      clrf    __status  ");                                    \
        _OS_SET_FSR_CUR_TASK_W(2);                                          \
        asm("      movf     __indf, w       ");                             \
        asm("      movwf    __pclath        ");                             \
        asm("      andlw    0x60 ");                                        \
        asm("      iorwf    __status, f  ");                                \
        _fsr--;                                                             \
        asm("      movf     __indf, w       ");                             \
        _fsr--;                                                             \
        asm("      movwf    __pcl     ");                                   \
        /* Now FSR points to OS_CurTask->State    */                        \
    }

//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
// Shell we work with bCanContinue flag? It is defined by OS_ENABLE_TTIMERS constant
//------------------------------------------------------------------------------
#ifdef OS_ENABLE_TTIMERS
    #define _OS_BSF_PCLATH_0()                      \
        asm("   bsf   __pclath, 0     ");           \
        asm("   btfss __pclath, 0     ");

    #define _OS_BCF_PCLATH_0()                      \
        asm("   bcf   __pclath, 0     ");

    #define _OS_INDF_CANCONTINUE()                  \
       _OS_bTaskCanContinue = 0;                    \
       if (_pclath & 0x01) _OS_bTaskCanContinue = 1;

#else
    #define _OS_BSF_PCLATH_0() 
    #define _OS_BCF_PCLATH_0()
    #define _OS_INDF_CANCONTINUE()
#endif


//------------------------------------------------------------------------------
// Save task return address
//------------------------------------------------------------------------------

#define _OS_SaveRetAddr()                                                   \
    {                                                                       \
        asm("\t global     __OS_temp        ");                             \
        asm("\t global     __OS_tempH       ");                             \
        asm("global  OS_SchedRetPoint   ");                                 \
        asm("global  OS_SchedRetPoint3   ");                                \
        asm("global  OS_ClearReady  ");                                     \
        asm("global  OS_ClearReadySetCanContinue  ");                       \
                                                                            \
        asm("OS_ClearReadySetCanContinue:  ");                              \
            _OS_BSF_PCLATH_0();                                             \
        asm("OS_ClearReady:  ");                                            \
            _OS_BCF_PCLATH_0();                                             \
        asm("OS_SchedRetPoint:   ");                                        \
            /* First we save RP1 and RP0 */                                 \
            _OS_SAVE_RP0_RP1();                                             \
            asm("   clrf    __status     ");                                \
            asm("   movwf   __OS_tempH    ");                               \
            _OS_temp = _fsr;                                                \
            _OS_SET_FSR_CUR_TASK_W(2);                                      \
            _indf = _OS_tempH;                                              \
            _fsr--;                                                         \
            _indf = _OS_temp;                                               \
            _fsr--;                                                         \
            _OS_bTaskReady = 1;                                             \
            asm("   btfss   __OS_tempH, 7");                                \
            asm("   goto    OS_SchedRetPoint3    ");                        \
            _OS_bTaskReady = 0;                                             \
            _OS_INDF_CANCONTINUE();                                         \
            _OS_RESTORE_RP0_RP1();                                          \
            asm("   return     ");                                          \
        asm("OS_SchedRetPoint3:      ");                                    \
            asm(" clrf __status");                                          \
    }
//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task and save context                                           */
/************************************************************************/
asm("_goto_OS_SchedRetPoint macro       ");
asm("   global  OS_SchedRetPoint        ");
asm("   local   task_ret_point          ");
asm("   movlw   low(task_ret_point)     ");
asm("   movwf   0x04                    ");
asm("   movlw   high(task_ret_point)    ");
asm("   ljmp    OS_SchedRetPoint        ");
asm("task_ret_point:                    ");
asm("   endm                            ");
//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task without saving context                                     */
/************************************************************************/
asm("_goto_OS_SchedRetPoint3 macro      ");
asm("   global  OS_SchedRetPoint3       ");
asm("   ljmp    OS_SchedRetPoint3       ");
asm("   endm                            ");
//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady flag                               */
/************************************************************************/
asm("_call_OS_ClearReady macro          ");
asm("   global  OS_ClearReady           ");
asm("   local   task_ret_point          ");
asm("   movlw   low(task_ret_point)     ");
asm("   movwf   0x04                    ");
asm("   movlw   0x80|high(task_ret_point)");
asm("   lcall   OS_ClearReady           ");
asm("task_ret_point:                    ");
asm("   endm                            ");
//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady and setting bCanContinue           */
/************************************************************************/
asm("_call_OS_ClearReadySetCanContinue macro    ");
asm("   global  OS_ClearReadySetCanContinue     ");
asm("   local   task_ret_point                  ");
asm("   movlw   low(task_ret_point)             ");
asm("   movwf   0x04                            ");
asm("   movlw   0x80|high(task_ret_point)       ");
asm("   lcall   OS_ClearReadySetCanContinue     ");
asm("task_ret_point:                            ");
asm("   endm                                    ");
//------------------------------------------------------------------------------



/************************************************************************/
/*                                                                      */
/************************************************************************/
#define _OS_GetReturnPoint()                asm(" _goto_OS_SchedRetPoint ");
#define _OS_ReturnNoSave()                  asm(" _goto_OS_SchedRetPoint3 ");
#define _OS_CLEAR_READY()                   asm(" _call_OS_ClearReady ");
#define _OS_CLEAR_READY_SET_CANCONTINUE()   asm(" _call_OS_ClearReadySetCanContinue ");

//------------------------------------------------------------------------------

#if defined(_ROMSIZE) && (_ROMSIZE <= 0x800)
    extern void  _OS_SET_FSR_CUR_TASK_W (char);
    extern void  _OS_SET_FSR_CUR_TASK (void);
#else
    #define _OS_SET_FSR_CUR_TASK()      {_fsr =  (_FSR_TYPE)_OS_CurTask; _SET_TASK_IRP();}
    #define _OS_SET_FSR_CUR_TASK_W(w)   {_fsr = ((_FSR_TYPE)_OS_CurTask) + w; _SET_TASK_IRP();}
#endif




    
    
    
//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR OLD STYLE STATIC TIMERS WORK
 *
 ******************************************************************************************/


#define __OS_Timer8Work(TIMER_ID,L)                                                                             \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID)>>3]&(1<<((TIMER_ID)&7)))) {                                                 \
            if (!++OS_Timers8[TIMER_ID])                                                                        \
                OS_Timeouts[(TIMER_ID)>>3]&=~(1<<((TIMER_ID)&7));                                               \
        }                                                                                                       \
    }


#define __OS_Timer16Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER16_POS)&7))))                   \
        if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+1)) {                                       \
                OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER16_POS)&7));               \
            };                                                                                                  \
        };                                                                                                      \
    }


#define __OS_Timer24Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER24_POS)&7))))                   \
        if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+1)) {                                       \
                OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER24_POS)&7));               \
            };                                                                                                  \
        };                                                                                                      \
    }



#define __OS_Timer32Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER32_POS)&7))))                   \
        if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+1)) {                                       \
                if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+2)) {                                   \
                    if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+3)) {                               \
                        OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER32_POS)&7));       \
                    };                                                                                          \
                };                                                                                              \
            };                                                                                                  \
        };                                                                                                      \
    }


//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR WORK WITH NEW STYLE STATIC TIMERS
 *
 ******************************************************************************************/

#if     OS_STIMER_SIZE == 1
    #define __OS_STimerWork(STIMER_ID, L)                                               \
        {                                                                               \
            if (OS_STimers[STIMER_ID] & 0x80) OS_STimers[STIMER_ID]++;                  \
        }
        
#elif   OS_STIMER_SIZE == 2
    #define __OS_STimerWork(STIMER_ID, L)                                               \
        {                                                                               \
            if (*((char*)&OS_STimers[STIMER_ID]+1) & 0x80) OS_STimers[STIMER_ID]++;     \
        }
        
#elif   OS_STIMER_SIZE == 4
    #define __OS_STimerWork(STIMER_ID, L)                                               \
        {                                                                               \
            if (*((char*)&OS_STimers[STIMER_ID]+3) & 0x80) OS_STimers[STIMER_ID]++;     \
        }
        
#endif


//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR WORK WITH TASK TIMERS
 *
 ******************************************************************************************/

#define ASM_OST_TCB_SIZE_CONST  asm(" ");
#define ASM_SET_BANK            asm(" ");


#if   OS_TTIMER_SIZE == 1
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay) {                                            \
                if (!++OS_TaskVars[TASK_ID].Timer)                                              \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
            }                                                                                   \
        }
#elif OS_TTIMER_SIZE == 2
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
                }                                                                               \
            }                                                                                   \
        }
#elif OS_TTIMER_SIZE == 4
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+2)) {             \
                        if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+3)) {         \
                            OS_TaskVars[TASK_ID].State.bDelay = 0;                              \
                        }                                                                       \
                    }                                                                           \
                }                                                                               \
            }                                                                                   \
        }

#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/******************************************************************************************/











 
/******************************************************************************************
 *
 *  WORK WITH DYNAMIC TIMERS
 *
 ******************************************************************************************/

#ifdef OS_ENABLE_DTIMERS

#if   OS_DTIMER_SIZE == 1
    #define OS_INC_DTIMER()                             \
        {                                               \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   bcf     __status, 2 ");             \
            asm("   incf    __indf, f   ");             \
            asm("   movwf   __fsr       ");             \
            if (ZERO) _OS_SetIndfTimerTimeout;          \
        }
#elif OS_DTIMER_SIZE == 2
    #define OS_INC_DTIMER()                             \
        {                                               \
            asm("   bcf     __status, 0 ");             \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 5       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 2       ");             \
            asm("   bsf     __status, 0 ");             \
            asm("   movwf   __fsr       ");             \
            if (CARRY) _OS_SetIndfTimerTimeout;         \
        }
#elif OS_DTIMER_SIZE == 4
    #define OS_INC_DTIMER()                             \
        {                                               \
            asm("   bcf     __status, 0 ");             \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 11      ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 8       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 5       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 2       ");             \
            asm("   bsf     __status, 0 ");             \
            asm("   movwf   __fsr       ");             \
            if (CARRY) _OS_SetIndfTimerTimeout;         \
        }
#endif


#define __OS_DTimersWork()                                  \
    {                                                       \
        IRP = 0;                                            \
        _fsr = (_FSR_TYPE) &_OS_DTimers;                    \
    REPEAT:                                                 \
        if (_OS_CheckIndfTimerNextEnable)                   \
        {                                                   \
            _fsr++;                                         \
            _fsr = _indf;                                   \
            if (!_OS_CheckIndfTimerRun) goto REPEAT;        \
            OS_INC_DTIMER();                                \
            goto REPEAT;                                    \
        }                                                   \
    }


#endif  // OS_ENABLE_DTIMER




/******************************************************************************************
 *
 *
 *
 ******************************************************************************************/


#endif
